﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Messaging;
using System.Text;
using System.Threading.Tasks;
using HotShot.Entities;
using HotShot.Entities.Messages;

namespace HotShot.Client
{
    public class HotShotClient
    {
        static MessageQueue _requestQueue;
        static MessageQueue _responseQueue;

        protected static MessageQueue InitMq(string direction)
        {
            string path;
            path = @".\private$\hotshot." + direction;

            var result = new MessageQueue(path)
            {
                Formatter = new XmlMessageFormatter(new[] { typeof(BaseMessage) }),
            };
            result.MessageReadPropertyFilter.CorrelationId = true;
            result.MessageReadPropertyFilter.SentTime = true;
            return result;
        }


        static HotShotClient()
        {
            EntityBaseExtender.Init(new List<Type>());

            _requestQueue = InitMq("in");
            _responseQueue = InitMq("out");
        }

        private T2 DoSynchronousCall<T, T2>(string command, T entity) 
            where T: EntityBase
            where T2: class
        {
            String cid;
            Message m = new Message(new BaseMessage
            {
                SenderAddress = null,
                ReturnAddress = null,
                Destination = null,
                MessageType = command,
                XmlPayload = entity.ToXml(),
            });

            _requestQueue.Send(m);
            cid = m.Id;
            Trace.WriteLine("cid: " + cid);

            var timeout = TimeSpan.FromMinutes(1);
            var final = DateTime.Now.Add(timeout);

            Message r = _responseQueue.ReceiveByCorrelationId(cid, timeout);
            var re = (r.Body as BaseMessage).XmlPayload.FromXml<T2>();
            return re;
        }


        public void Store(StorageEntity entity)
        {
            StorageEntity re = DoSynchronousCall<StorageEntity, StorageEntity>("Store", entity);

            Trace.WriteLine(String.Format("Message stored successfully in {0} node(s)", re.StoreIndex));
        }

        public StorageEntity Retrieve(string key)
        {
            List<StorageEntity> re = DoSynchronousCall<StorageEntity, List<StorageEntity>>("Retrieve", new StorageEntity { Key = key, });
            Trace.WriteLine(String.Format("Message was retrieved from {0} of {1} node(s)", re[0].StoreIndex, re[0].StoreCount));

            return re[0];
        }


    }
}
